package com.monitor.log.biz.core;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.core.NamedThreadLocal;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import com.ms.client.monitor.api.pojo.BizLog;
import com.ms.client.monitor.api.pojo.BizLogDtl;
import com.ms.client.monitor.api.service.MonitorApiBizLogService;
import com.netflix.discovery.EurekaClient;
import com.system.comm.utils.FrameHttpRequestUtil;
import com.system.comm.utils.FrameJsonUtil;
import com.system.comm.utils.FrameSpringBeanUtil;
import com.system.comm.utils.FrameStringUtil;
import com.system.comm.utils.FrameTimeUtil;

/**
 * 业务日志工具类
 * 	在配置文件中新增 save.log.open=1；代表打开记录日志
 * 	在配置文件中新增 save.log.exclude.url=/main/index；代表不进行日志记录的路径[多个,分隔]
 * @author yuejing
 * @date 2019年12月3日 下午4:31:40
 */
public class BizLogUtil {

	private static final ThreadLocal<Date> beginTimeThreadLocal = new NamedThreadLocal<Date>("ThreadLocal beginTime");
	private static final ThreadLocal<String> curUriThreadLocal = new NamedThreadLocal<String>("ThreadLocal curUri");
	private static final ThreadLocal<String> reqParam1ThreadLocal = new NamedThreadLocal<String>("ThreadLocal reqParam1");
	private static final ThreadLocal<String> reqParam2ThreadLocal = new NamedThreadLocal<String>("ThreadLocal reqParam2");
	private static final ThreadLocal<String> reqParam3ThreadLocal = new NamedThreadLocal<String>("ThreadLocal reqParam3");

	public static String getTraceId() {
		/*String traceId = traceIdThreadLocal.get();
		if (FrameStringUtil.isEmpty(traceId)) {
			traceId = traceId();
			//FrameNoUtil.uuid();
			traceIdThreadLocal.set(traceId);
		}*/
		return traceId();
	}
	/*public static void setTraceId(String traceId) {
		traceIdThreadLocal.set(traceId);
	}*/

	public static void getBeginTime() {
		beginTimeThreadLocal.get();
	}
	public static void setBeginTime(Date beginTime) {
		beginTimeThreadLocal.set(beginTime);
	}
	public static String getReqParam1() {
		return reqParam1ThreadLocal.get();
	}
	public static void setReqParam1(String reqParam1) {
		reqParam1ThreadLocal.set(reqParam1);
	}
	public static String getReqParam2() {
		return reqParam2ThreadLocal.get();
	}
	public static void setReqParam2(String reqParam2) {
		reqParam2ThreadLocal.set(reqParam2);
	}
	public static String getReqParam3() {
		return reqParam3ThreadLocal.get();
	}
	public static void setReqParam3(String reqParam3) {
		reqParam3ThreadLocal.set(reqParam3);
	}
	public static String getCurUri() {
		return curUriThreadLocal.get();
	}
	public static void setCurUri(String curUri) {
		curUriThreadLocal.set(curUri);
	}
	public static String getSpanId() {
		/*String spanId = spanIdThreadLocal.get();
		if (FrameStringUtil.isEmpty(spanId)) {
			spanId = spanId();
			//FrameNoUtil.uuid();
			spanIdThreadLocal.set(spanId);
		}*/
		return spanId();
	}
	/*public static void setSpanId(String spanId) {
		spanIdThreadLocal.set(spanId);
	}*/

	public static String spanId() {
		/*Tracer tracer = FrameSpringBeanUtil.getBean(Tracer.class);
		return HexCodec.toLowerHex(tracer.currentSpan().context().spanId());*/
		return BizLogSpanIdUtil.getSpanId();
	}
	public static String traceId() {
		/*Tracer tracer = FrameSpringBeanUtil.getBean(Tracer.class);
		return HexCodec.toLowerHex(tracer.currentSpan().context().traceId());*/
		return BizLogTraceIdUtil.getTraceId();
	}
	/**
	 * 保存接口响应信息
	 * @param value
	 */
	/*public static void saveLogDtlResponse(Object value) {
		saveLogDtl(HTTP_RESPONSE, value);
	}*/
	public static List<String> excludeUrls() {
		return BizLogData.getExcludeUrl();
	}
	/**
	 * 当前请求是否保存日志
	 * @return
	 */
	public static boolean isSave() {
		if (!BizLogData.isDelaySave()) {
			return false;
		}
		String requestUri = getCurUri();
		// 排除固定地址的日志记录
		if (FrameStringUtil.isNotEmpty(requestUri)) {
			List<String> excludeUrls = BizLogUtil.excludeUrls();
			for (String path : excludeUrls) {
				if (requestUri.contains(path)) {
					return false;
				}
			}
		}
		return true;
	}
	/**
	 * 是否开启记录日志
	 * @return	{true:记录日志/false:关闭记录日志}
	 */
	public static boolean isOpen() {
		Environment env = FrameSpringBeanUtil.getBean(Environment.class);
		String saveLogOpen = env.getProperty("save.log.open");
		if (!"1".equals(saveLogOpen)) {
			return false;
		}
		return true;
	}
	/**
	 * 保存信息
	 * @param key
	 * @param value
	 */
	public static void saveLogDtl(String key, Object value) {
		BizLog bizLog = new BizLog();
		String traceId = BizLogUtil.getTraceId();
		bizLog.setTraceId(traceId);
		bizLog.setReqTime(FrameTimeUtil.getTime());
		bizLog.setReqParam1(BizLogUtil.getReqParam1());
		bizLog.setReqParam2(BizLogUtil.getReqParam2());
		bizLog.setReqParam3(BizLogUtil.getReqParam3());
		String spanId = BizLogUtil.getSpanId();
		List<BizLogDtl> dtls = new ArrayList<BizLogDtl>();
		String valueString = null;
		if (value != null) {
			if (value instanceof String) {
				valueString = value.toString();
			} else {
				valueString = FrameJsonUtil.toString(value);
			}
		}
		dtls.add(new BizLogDtl(spanId, traceId, System.currentTimeMillis(),
				key, valueString));
		bizLog.setDtls(dtls);
		saveLog(bizLog);
	}

	/**
	 * 保存完整日志记录
	 * @param bizLog
	 */
	public static void saveLog(BizLog bizLog) {
		if (!BizLogUtil.isOpen()) {
			return;
		}
		// 排除固定地址的日志记录
		if (!BizLogUtil.isSave()) {
			return;
		}
		MonitorApiBizLogService apiBizLogService = FrameSpringBeanUtil.getBean(MonitorApiBizLogService.class);
		ThreadPoolTaskExecutor threadPoolTaskExecutor = FrameSpringBeanUtil.getBean(ThreadPoolTaskExecutor.class);
		threadPoolTaskExecutor.execute(new SaveLogThread(bizLog, apiBizLogService));
	}

	/**
	 * 保存日志线程
	 */
	private static class SaveLogThread implements Runnable {
		private BizLog bizLog;
		private MonitorApiBizLogService apiBizLogService;

		public SaveLogThread(BizLog bizLog, MonitorApiBizLogService apiBizLogService) {
			this.bizLog = bizLog;
			this.apiBizLogService = apiBizLogService;
		}

		@Override
		public void run() {
			String reqTime = null;
			if (bizLog.getReqTime() != null) {
				reqTime = FrameTimeUtil.parseString(bizLog.getReqTime());
			}
			apiBizLogService.save(bizLog.getTraceId(), bizLog.getReqParam1(),
					bizLog.getReqParam2(), bizLog.getReqParam3(),
					reqTime, FrameJsonUtil.toString(bizLog.getDtls()));
		}
	}

	public static String getServiceId() {
		Environment env = FrameSpringBeanUtil.getBean(Environment.class);
		return env.getProperty("spring.application.name");
	}
	public static void saveLogZuulFilter(HttpServletRequest request, String responseResult) {
		//本机的IP
		String remoteAddr = BizLogUtil.getIp();
		//请求的Uri
		String requestUri = request.getRequestURI();
		BizLogUtil.setCurUri(requestUri);
		String requestUrl = request.getRequestURL().toString();
		BizLog bizLog = new BizLog();
		String traceId = BizLogUtil.getTraceId();
		bizLog.setTraceId(traceId);
		bizLog.setReqTime(FrameTimeUtil.getTime());
		bizLog.setReqParam1(BizLogUtil.getReqParam1());
		bizLog.setReqParam2(BizLogUtil.getReqParam2());
		bizLog.setReqParam3(BizLogUtil.getReqParam3());
		String spanId = BizLogUtil.getSpanId();
		List<BizLogDtl> dtls = new ArrayList<BizLogDtl>();
		Long reqTime = BizLogData.getZuulReqTime();
		if (reqTime == null) {
			reqTime = System.currentTimeMillis();
		}
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_PATH, requestUri));
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_URL, requestUrl));
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_REMOTE_ADDR, remoteAddr));
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_SERVICE_ID, BizLogUtil.getServiceId()));
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_REQUEST_TIME, FrameTimeUtil.parseString(new Date(reqTime))));
		Map<String, Object> params = FrameHttpRequestUtil.getReqParams(request);
		if (params.size() == 0) {
			params = FrameHttpRequestUtil.getReqBodyParams(request);
		}
		String paramString = FrameJsonUtil.toString(params);
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_PARAMS, paramString));
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_RESPONSE, responseResult));
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_RESPONSE_TIME, FrameTimeUtil.parseString(new Date(System.currentTimeMillis()))));
		bizLog.setDtls(dtls);

		//通过线程池来执行日志保存
		BizLogUtil.saveLog(bizLog);
	}
	/**
	 * 获取请求ip
	 */
	public static String getIp() {
		EurekaClient eurekaClient = FrameSpringBeanUtil.getBean(EurekaClient.class);
		String localIp = eurekaClient.getApplicationInfoManager().getInfo().getIPAddr();
		/*
		 String localIp = null;
		 try {
			InetAddress ia = InetAddress.getLocalHost();
			localIp = ia.getHostAddress();
		} catch (UnknownHostException e) {
			localIp = "UnknownHost";
		}*/
		return localIp;
	}
	
	/*public static void main(String[] args) {
		String ip = getIp();
		System.out.println(ip);
	}*/
}
